package tr.com.oyunus.server.command.router.impl;

import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.util.CharsetUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import tr.com.oyunus.server.command.Command;
import tr.com.oyunus.server.command.exception.NoSuchCommandException;
import tr.com.oyunus.server.command.handler.CommandHandler;
import tr.com.oyunus.server.command.router.CommandRouter;
import tr.com.oyunus.server.command.transform.CommandDeserializer;
import tr.com.oyunus.server.exception.OyunusException;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Component
public class NettyHttpCommandRouter implements CommandRouter<MessageEvent> {
    @Autowired
    CommandDeserializer<String> defaultDeserializer;
    @Autowired
    List<CommandHandler> commandHandlerList;
    Map<String, List<CommandHandler>> routeMap = new HashMap<String, List<CommandHandler>>();

    @Override
    public void routeCommand(MessageEvent rawMessage) {

        HttpRequest request = (HttpRequest) rawMessage.getMessage();

        String commandAsString = request.getContent().toString(CharsetUtil.UTF_8);
        try {
            Command command = defaultDeserializer.deserialize(commandAsString);
            dispatchCommand(command, rawMessage);
        } catch (Exception e) {
            rawMessage.getChannel().write(e.getClass().getSimpleName());
            rawMessage.getChannel().write(e.getMessage());
            rawMessage.getChannel().close();
        }
    }


    private void dispatchCommand(Command command, MessageEvent source) throws OyunusException {

        List<CommandHandler> commandHandlers = routeMap.get(command.getFunction());
        if (commandHandlers == null)
            throw new NoSuchCommandException(command.getFunction());

        for (CommandHandler commandHandler : commandHandlers) {
            commandHandler.handleCommand(command, source);
        }
    }

    @PostConstruct
    private void createRouteMap() {
        if (commandHandlerList == null)
            return; // No handler to route.

        for (CommandHandler handler : commandHandlerList) {
            for (String commandName : handler.canHandle()) {
                List<CommandHandler> handlers = routeMap.get(commandName);
                if (handlers == null) {
                    handlers = new ArrayList<CommandHandler>(2);
                    routeMap.put(commandName, handlers);
                }
                handlers.add(handler);

            }
        }
    }
}
